package com.bupt.service.common.impl;

import com.bupt.Factory.ProjectFactory;
import com.bupt.basic.BasicNetWork;
import com.bupt.basic.IBasicNetWork;
import com.bupt.basic.Project;
import com.bupt.config.interceptor.thread.CurrentUserInfo;
import com.bupt.constants.InitConstants;
import com.bupt.dto.sys.LoginUserDto;
import com.bupt.dto.sys.UserDto;
import com.bupt.dto.network.NodeDto;
import com.bupt.entity.*;
import com.bupt.exception.BaseException;
import com.bupt.service.common.LinkService;
import com.bupt.service.common.NodeService;
import com.bupt.service.system.SysLoginService;
import com.bupt.utils.LinkStatusString;
import com.bupt.utils.LocalVerify;
import lombok.Data;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.Serializable;
import java.util.*;

@Service("nodeService")
public class NodeServiceImpl implements NodeService {

    private static final Object lock = new Object();
    private static final String successListKey = "successList"; // 成功的列表
    private static final String failListKey = "failList"; //失败的列表
    @Resource
    private CurrentUserInfo userInfo;


    //添加节点
    @Override
    public Object addNode(UserDto userDto,String id, String nodeName, int year, int completedYear, int serviceLength, int capacity, Double longitude, Double latitude, String code) throws BaseException {
        //得到当前操作的用户
        synchronized (lock) {
            userDto = userInfo.getCurrentOptUser();
                // 新增节点
                // 采用hashcode 的 方式 存储ID
                BasicNetWork.BasicNode node = new BasicNetWork.BasicNode(String.valueOf(nodeName.hashCode()), nodeName, code,
                        Double.valueOf(longitude), Double.valueOf(latitude),year,completedYear,
                        serviceLength,capacity);
                Map<String, List<AddNodeDto>> resMap =
                        this.addNodeToBasicNetWork(userDto,id, Collections.singletonList(node));

                if (resMap.get(failListKey).size() != 0)
                    throw new BaseException(resMap.get(failListKey).get(0).getReason());
                return  getProjectNodeList(id);
        }
    }

    public Map<String, List<AddNodeDto>> addNodeToBasicNetWork(UserDto userDto,String id, List<BasicNetWork.BasicNode> nodes)
            throws BaseException {
        if (null != nodes && nodes.size() > 0) {
            synchronized (lock) {
                // 设置返回的值
                List<AddNodeDto> successList = new ArrayList<AddNodeDto>();
                List<AddNodeDto> failList = new ArrayList<AddNodeDto>();
                // 获取当前系统网络的基础文件
                Project project = ProjectFactory.getObjectFromFile(id, ProjectFactory.storePath);
                BasicNetWork basicNetWork = project.getBasicNetWork();

                for (BasicNetWork.BasicNode node : nodes) {
                    try {
                        LocalVerify.verifyString(node.getName(), "节点名称");
                        LocalVerify.verifyString(node.getCode(), "节点编码");
                        if (node.getPointX() == null) throw new BaseException("经度必填");
                        if (node.getPointY() == null) throw new BaseException("纬度必填");
                        if (node.getYear() == null) throw new BaseException("开通年份必填");
                        // 当前的基础网络是存在当前的节点的信息的，那么就应该进行导入的操作
                        if(basicNetWork!=null) {
                            if (basicNetWork.getNodeNameSet().contains(node.getName()))
                                throw new BaseException("基础网络文件存在【" + node.getName() + "】节点，请进行导入节点操作");
                        }
                        // 设置节点的信息
                        // 采用hashCOde 来保证
                        node.setNodeId(String.valueOf(node.getName().hashCode()));
                        Date nowTime = new Date();
                        node.setCreateDate(nowTime);
                        node.setCreateId(userDto.getUId());
                        node.setCreateName(userDto.getUserName());
                        node.setIsOrigin(false);
                        // 基础网络添加节点操作 issue
                        basicNetWork.addNode(node);
                        successList.add(new AddNodeDto(node, "添加成功"));
                    } catch (Exception e) {
                        failList.add(new AddNodeDto(node, e.getMessage()));
                    }
                }// for (BasicNetWork.BasicNode node : nodes)
                // 返回操作
                Map<String, List<AddNodeDto>> res = new HashMap<>();
                res.put(successListKey, successList);
                res.put(failListKey, failList);
                // 更新网络信息
                updateProject(project);
                return res;
            }
        } else {
            //// if (null != nodes && nodes.size() > 0)
            throw new BaseException("至少有一个节点");
        }
    }


    //删除节点
    @Override
    public Object deleteNode(UserDto userDto,String projectId, String nodeId) throws BaseException {
        //辨别基本信息
        synchronized (lock) {
                LocalVerify.verifyString(projectId, "项目ID");
                LocalVerify.verifyString(nodeId, "节点ID");
                Project project = ProjectFactory.getObjectFromFile(projectId, ProjectFactory.storePath);
                if (project == null) throw new BaseException("项目不存在");
                List<IBasicNetWork.BasicNode> commonNodes = project.getBasicNetWork().getNodeList();
            IBasicNetWork.BasicNode commonNode = project.searchNodeById(nodeId);
                if (commonNode == null) throw new BaseException("此节点不存在");


                List<IBasicNetWork.BasicLink> fiberLinks = project.getBasicNetWork().getFiberLinks();
                Iterator<IBasicNetWork.BasicLink> iterator = fiberLinks.iterator();
                while (iterator.hasNext()) {
                    IBasicNetWork.BasicLink link = iterator.next();
                    /*IBasicNetWork.BasicNode fromNode = project.searchNodeById(link.getNodeHead());
                    IBasicNetWork.BasicNode toNode=project.searchNodeById(link.getNodeTail());*/
                    if (link.getNodeHead().equalsIgnoreCase(nodeId)) throw new BaseException("不能删除该节点，该节点存在邻边");
                    if (link.getNodeTail().equalsIgnoreCase(nodeId)) throw new BaseException("不能删除该节点，该节点存在邻边");
                }

                if (!commonNodes.remove(commonNode)) throw new BaseException("删除节点失败");
                project.getBasicNetWork().removeNode(nodeId);
                boolean b = ProjectFactory.saveObjectDataToFile(project, projectId, ProjectFactory.storePath);
                if (!b) throw new BaseException("固化失败");

            return getProjectNodeList(projectId);
        }
    }


    //更新节点
    @Override
    public Object updateNode(UserDto userDto, String projectId, String nodeId, String nodeName,
                             int year, int completedYear, int serviceLength, double longitude, double latitude, String code,
                             int capacity) throws BaseException {
        synchronized (lock) {

                LocalVerify.verifyString(projectId, "项目ID");
                LocalVerify.verifyString(nodeId, "节点ID");
                userDto = userInfo.getCurrentOptUser();
                Project project = ProjectFactory.getObjectFromFile(projectId, ProjectFactory.storePath);
                if (project == null) throw new BaseException("项目不存在");
                if (project.getBasicNetWork().getNodeList()!= null) {
                    for (IBasicNetWork.BasicNode commonNode : project.getBasicNetWork().getNodeList()) {
                        if (commonNode.getName().equals(nodeName) && !commonNode.getNodeId().equals(nodeId))
                            throw new BaseException("节点名字已被占用");
                        if(commonNode.getCode().equals(code)&&!commonNode.getNodeId().equals(nodeId))throw new BaseException("节点编码重复");
                    }
                    BasicNetWork.BasicNode node = new BasicNetWork.BasicNode(nodeId, nodeName, code,
                            longitude, latitude, year,completedYear, serviceLength, capacity);
                          node.updateSelf(node);

                    for (IBasicNetWork.BasicNode basicNode : project.getBasicNetWork().getNodeList()) {
                        if(basicNode.getNodeId().equals(nodeId)){
                            basicNode.updateSelf(node);
                        }
                    }
                }
                boolean b = ProjectFactory.saveObjectDataToFile(project, projectId, ProjectFactory.storePath);
                if (!b) throw new BaseException("固化失败");

            return getProjectNodeList(projectId);
        }
    }

        //获取节点列表
    @Override
    public Object getProjectNodeList(UserDto userDto, String projectId) throws BaseException {
        LocalVerify.verifyString(projectId,"项目ID");

      return  this.getProjectNodeList(projectId);
    }

    public Object getProjectNodeList(String projectId) throws BaseException{
        Project project = ProjectFactory.getObjectFromFile(projectId, ProjectFactory.storePath);
        if(project==null)throw new BaseException("项目不存在");
        List<IBasicNetWork.BasicNode> commonNodes = project.getBasicNetWork().getNodeList();
        ArrayList<NodeDto> list = new ArrayList<>();
        for (IBasicNetWork.BasicNode commonNode : commonNodes) {
            NodeDto nodeDto = new NodeDto(commonNode.getNodeId(), commonNode.getName(), commonNode.getCode(), commonNode.getPointX(), commonNode.getPointY(), commonNode.getYear(), commonNode.getCompletedYear(), commonNode.getServiceLength(),
                    commonNode.getCapacity());
            list.add(nodeDto);
        }
        return list;
    }

    private void updateProject(Project project) throws BaseException {
        boolean b = ProjectFactory.saveObjectDataToFile(project, project.getId(), ProjectFactory.storePath);
        if (!b) throw new BaseException("文件固化失败");
    }
    @Data
    class AddNodeDto implements Serializable {
        private static final long serialVersionUID = -5237463257289771638L;
        private IBasicNetWork.BasicNode node;
        private String reason;

        public AddNodeDto(IBasicNetWork.BasicNode node, String reason) {
            this.node = node;
            this.reason = reason;
        }
    }


}

